/** \file    type.h
  * \brief   common types of image lib
  * \date    2001 - 2003
  * \author  Fedor Chelnokov
  * \version $Header: /home/cscom1r4/cvsroot/cs/include/imglib/type.h,v 1.4 2007/07/12 20:30:10 cscom1r4 Exp $
  */

#ifndef _type_h_
#define _type_h_

#include <iostream>
#include "typelib/types.h"
#include "xtd/Arr2D.h"
#include "new_exception.h"

namespace types {
	template <class T> struct basic_affine;
}
using namespace types;

namespace img {

/**
 * x(t+1)=a0+(a1+1)x+a2y+a3xx+a4xy+a5yy
 * y(t+1)=b0+b1x+(b2+1)y+b3xx+b4xy+b5yy
 */
struct QuadraticForm
{
	union {
		struct {
			float a0, a1, a2, a3, a4, a5;
			float b0, b1, b2, b3, b4, b5;
		};
		float p[12];
	};

	void clear() 
		{ for (int i = 0; i != 12; ++i)
			p[i] = 0; }
	void identity()
		{ clear(); }
	bool affine() const
		{ return a3==0 && a4==0 && a5==0 && b3==0 && b4==0 && b5==0; }
	bool translation() const
		{ return a1==0 && a2==0 && b1==0 && b2==0 && affine(); }

	template <class T>
	void assign(const basic_affine<T> & a);

	float_point operator()(float x, float y) const {
		return float_point(
			a0 + x*(1+a1) + y*a2 + x*x*a3 + x*y*a4 + y*y*a5,
			b0 + x*b1 + y*(1+b2) + x*x*b3 + x*y*b4 + y*y*b5
		);
	}
	float_point operator()(const float_point & p) const {
		return operator()(p.x, p.y);
	}

	QuadraticForm & translate(float x, float y) {
		a0 += x;
		b0 += y;
		return * this;
	}
	QuadraticForm & translate(const float_point & p) 
		{ return translate(p.x, p.y); }
	///makes rigid transformation from rigid+zoom
	void rigid() {
		assert(a1 == b2 && a2 == -b1);
		double s = _hypot(a1+1, a2);
		a1 = b2 = (float) ((a1+1) / s) - 1;
		b1 = - (a2 = (float) (a2 / s));
	}

	///saves into stream
	void write_xml(std::ostream& os) const;
	///loads from entire file
	//\exception BadIniFileFormat
	void read_xml(const char *filename);

	QuadraticForm & operator *=(float c)
		{ for (int i = 0; i != 12; ++i)
			p[i] *= c; 
		  return *this; }
	QuadraticForm & operator +=(const QuadraticForm &a)
		{ for (int i = 0; i != 12; ++i)
			p[i] += a.p[i];
		  return *this; }
	///combination of transformations
	friend img::QuadraticForm 
		operator *(const img::QuadraticForm &f1, const img::QuadraticForm &f0);
};

typedef YATL::Arr2D<Point2f> PntArr2f;

EXCEPTION( BadQfFileFormat, "Incomplete data or corrupted file format of QuadraticForm-xml file" )
EXCEPTION( QfFileNotFound, "QuadraticForm file not found" )

} //img

template <> 
inline void inverse(img::QuadraticForm & f) {
	for (int i = 0; i != 12; ++i)
		f.p[i] = -f.p[i];
}

///formatted output
std::ostream& operator <<(std::ostream& os, const img::QuadraticForm& qf);
class delimQf {
public:
	delimQf(const img::QuadraticForm& qf, char delim) : _qf(qf), _delim(delim) {}
	friend std::ostream& operator <<(std::ostream& os, const delimQf& d);
private:
	const img::QuadraticForm& _qf;
	char _delim;
};

//////////////////////
// XML input/output //
//////////////////////

namespace xml {
	class stem;
	stem & operator || (stem & s, img::QuadraticForm & q);
	stem & operator << (stem & s, const img::QuadraticForm & f);
	const stem & operator >> (const stem & s, img::QuadraticForm & f);
} //namespace xml

#endif //_type_h_
